package git

import (
	"crypto/md5"
	"fmt"
	"log"
	"os"
	"os/exec"
	"strings"
	"time"

	"github.com/lxn/walk"
)

// execGitCommand 执行 git 命令并返回错误
func execGitCommand(args ...string) error {
	cmd := exec.Command("git", args...)
	if output, err := cmd.CombinedOutput(); err != nil {
		return fmt.Errorf("%s: %w", string(output), err)
	}
	return nil
}

func Push(remote, branch string) error {
	// 先检查远程仓库是否可访问
	if err := checkRemoteAccess(remote); err != nil {
		// 如果检查失败，询问用户是否继续
		if walk.MsgBox(nil, "连接警告",
			fmt.Sprintf("无法连接到远程仓库：%v\n是否仍要尝试推送？", err),
			walk.MsgBoxYesNo|walk.MsgBoxIconWarning) != walk.DlgCmdYes {
			return fmt.Errorf("用户取消了推送")
		}
		log.Printf("用户选择继续推送，尽管连接检查失败")
	}

	// 获取远程分支列表
	branches, err := ListBranches(remote)
	if err == nil {
		// 检查分支是否存在
		branchExists := false
		for _, b := range branches {
			if b == branch {
				branchExists = true
				break
			}
		}

		// 如果分支不存在，询问是否创建
		if !branchExists {
			if walk.MsgBox(nil, "分支确认",
				fmt.Sprintf("分支 '%s' 不存在，是否创建？", branch),
				walk.MsgBoxYesNo|walk.MsgBoxIconQuestion) == walk.DlgCmdYes {
				if err := CheckoutBranch(branch, true); err != nil {
					return fmt.Errorf("创建分支失败: %v", err)
				}
			} else {
				return fmt.Errorf("用户取消了分支创建")
			}
		}
	} else {
		log.Printf("获取分支列表失败: %v，将直接尝试推送", err)
	}

	// 尝试直接推送
	err = execGitCommand("push", remote, branch)
	if err == nil {
		return nil
	}

	// 如果是因为需要 pull，则尝试先 pull
	if strings.Contains(err.Error(), "fetch first") ||
		strings.Contains(err.Error(), "Updates were rejected") {

		// 先尝试普通拉取
		err = execGitCommand("pull", remote, branch)
		if err != nil {
			log.Printf("普通拉取失败: %v", err)

			// 尝试带 --allow-unrelated-histories 的拉取
			err = execGitCommand("pull", remote, branch, "--allow-unrelated-histories")
			if err != nil {
				log.Printf("允许不相关历史的拉取也失败: %v", err)

				// 如果拉取失败，提示用户选择是否强制推送
				if walk.MsgBox(nil, "推送确认",
					"无法自动合并远程更改。是否要强制推送本地更改？\n"+
						"警告：这将覆盖远程仓库的更改！",
					walk.MsgBoxYesNo|walk.MsgBoxIconWarning) == walk.DlgCmdYes {

					log.Printf("用户选择强制推送...")
					if err := execGitCommand("push", "-f", remote, branch); err != nil {
						return fmt.Errorf("强制推送失败: %v", err)
					}
					return nil
				}
				return fmt.Errorf("用户取消了强制推送")
			}
		}

		// 拉取成功后再次尝试推送
		if err := execGitCommand("push", remote, branch); err != nil {
			return fmt.Errorf("拉取后推送仍然失败: %v", err)
		}
		return nil
	}

	// 其他错误直接返回
	return fmt.Errorf("推送失败: %v", err)
}

func pushOnce(repoURL, branch string) error {
	// 检查当前目录是否是git仓库
	if err := checkGitRepo(); err != nil {
		return err
	}

	// 生成唯一的远程仓库名称
	// 使用 MD5 哈希来生成一个有效的远程仓库名称
	hasher := md5.New()
	hasher.Write([]byte(repoURL))
	remoteName := fmt.Sprintf("temp_%x", hasher.Sum(nil))

	// 清理可能存在的同名远程仓库
	cleanupCmd := exec.Command("git", "remote", "remove", remoteName)
	cleanupCmd.Run() // 忽略错误，因为可能不存在

	// 添加远程仓库
	addCmd := exec.Command("git", "remote", "add", remoteName, repoURL)
	if output, err := addCmd.CombinedOutput(); err != nil {
		return fmt.Errorf("添加远程仓库失败: %s: %w", string(output), err)
	}
	defer func() {
		removeCmd := exec.Command("git", "remote", "remove", remoteName)
		if err := removeCmd.Run(); err != nil {
			log.Printf("清理远程仓库失败: %v", err)
		}
	}()

	// 检查分支是否存在
	checkBranchCmd := exec.Command("git", "rev-parse", "--verify", branch)
	if err := checkBranchCmd.Run(); err != nil {
		return fmt.Errorf("分支 %s 不存在", branch)
	}

	// 推送到远程仓库
	pushCmd := exec.Command("git", "push", remoteName, branch)
	if output, err := pushCmd.CombinedOutput(); err != nil {
		return fmt.Errorf("推送失败: %s: %w", string(output), err)
	}

	return nil
}

// 添加一个检查远程仓库是否可访问的函数
func checkRemoteAccess(repoURL string) error {
	// 设置超时时间
	cmd := exec.Command("git", "ls-remote", "--exit-code", repoURL)
	cmd.Env = append(os.Environ(),
		"GIT_TERMINAL_PROMPT=0",  // 禁用终端提示
		"GIT_SSL_NO_VERIFY=true", // 忽略 SSL 验证
	)

	// 设置超时
	done := make(chan error, 1)
	go func() {
		if output, err := cmd.CombinedOutput(); err != nil {
			done <- fmt.Errorf("远程仓库访问失败: %s: %w", string(output), err)
		} else {
			done <- nil
		}
	}()

	// 等待结果或超时
	select {
	case err := <-done:
		return err
	case <-time.After(10 * time.Second):
		if cmd.Process != nil {
			cmd.Process.Kill()
		}
		return fmt.Errorf("连接超时")
	}
}

func checkGitRepo() error {
	// 检查是否是 git 仓库
	cmd := exec.Command("git", "rev-parse", "--git-dir")
	if err := cmd.Run(); err != nil {
		return fmt.Errorf("当前目录不是git仓库: %w", err)
	}

	// 不再检查未提交的更改，因为这不应该阻止推送操作
	return nil
}

// 将函数名改为大写开头，使其可导出
func HasUncommittedChanges() (bool, error) {
	statusCmd := exec.Command("git", "status", "--porcelain")
	output, err := statusCmd.Output()
	if err != nil {
		return false, fmt.Errorf("检查git状态失败: %w", err)
	}
	return len(output) > 0, nil
}

func Commit(message string) error {
	// 添加所有更改
	addCmd := exec.Command("git", "add", ".")
	if err := addCmd.Run(); err != nil {
		return fmt.Errorf("git add 失败: %w", err)
	}

	// 提交更改
	commitCmd := exec.Command("git", "commit", "-m", message)
	if output, err := commitCmd.CombinedOutput(); err != nil {
		return fmt.Errorf("git commit 失败: %s: %w", string(output), err)
	}

	return nil
}

func GetWorkingDir() string {
	dir, err := os.Getwd()
	if err != nil {
		log.Printf("获取当前目录失败: %v", err)
		return ""
	}

	// 检查是否是git仓库
	if err := checkGitRepo(); err != nil {
		log.Printf("当前目录不是git仓库: %v", err)
		return ""
	}

	return dir
}

func SetWorkingDir(path string) error {
	// 先检查目录是否存在
	if _, err := os.Stat(path); err != nil {
		return fmt.Errorf("目录不存在: %w", err)
	}

	// 切换到目标目录
	if err := os.Chdir(path); err != nil {
		return fmt.Errorf("切换目录失败: %w", err)
	}

	// 检查是否是git仓库
	if err := checkGitRepo(); err != nil {
		// 如果不是git仓库，切回原目录
		return fmt.Errorf("不是有效的git仓库: %w", err)
	}

	return nil
}

func SetGitConfig(name, email string, global bool) error {
	scope := "--local"
	if global {
		scope = "--global"
	}

	// 设置用户名
	if name != "" {
		cmd := exec.Command("git", "config", scope, "user.name", name)
		if err := cmd.Run(); err != nil {
			return fmt.Errorf("设置用户名失败: %w", err)
		}
	}

	// 设置邮箱
	if email != "" {
		cmd := exec.Command("git", "config", scope, "user.email", email)
		if err := cmd.Run(); err != nil {
			return fmt.Errorf("设置邮箱失败: %w", err)
		}
	}

	return nil
}

func GetGitConfig(global bool) (name string, email string, err error) {
	scope := "--local"
	if global {
		scope = "--global"
	}

	// 获取用户名
	nameCmd := exec.Command("git", "config", scope, "--get", "user.name")
	nameOutput, err := nameCmd.Output()
	if err == nil {
		name = strings.TrimSpace(string(nameOutput))
	}

	// 获取邮箱
	emailCmd := exec.Command("git", "config", scope, "--get", "user.email")
	emailOutput, err := emailCmd.Output()
	if err == nil {
		email = strings.TrimSpace(string(emailOutput))
	}

	return
}

// 添加 Pull 函数
func Pull(remote, branch string) error {
	// 允许合并不相关的历史
	return execGitCommand("pull", remote, branch, "--allow-unrelated-histories")
}

// GetRemoteURL 获取指定名称的远程仓库地址
func GetRemoteURL(remoteName string) (string, error) {
	cmd := exec.Command("git", "remote", "get-url", remoteName)
	output, err := cmd.Output()
	if err != nil {
		return "", fmt.Errorf("获取远程仓库地址失败: %w", err)
	}
	return strings.TrimSpace(string(output)), nil
}

// SetRemoteURL 设置远程仓库地址
func SetRemoteURL(remoteName, url string) error {
	// 检查远程仓库是否存在
	checkCmd := exec.Command("git", "remote")
	output, err := checkCmd.Output()
	remoteExists := false
	if err == nil {
		remotes := strings.Split(string(output), "\n")
		for _, remote := range remotes {
			if strings.TrimSpace(remote) == remoteName {
				remoteExists = true
				break
			}
		}
	}

	var cmd *exec.Cmd
	if remoteExists {
		// 如果远程仓库已存在，则设置新地址
		cmd = exec.Command("git", "remote", "set-url", remoteName, url)
	} else {
		// 如果远程仓库不存在，则添加新的远程仓库
		cmd = exec.Command("git", "remote", "add", remoteName, url)
	}

	if output, err := cmd.CombinedOutput(); err != nil {
		return fmt.Errorf("设置远程仓库地址失败: %s: %w", string(output), err)
	}

	return nil
}

// ListRemotes 列出所有远程仓库
func ListRemotes() (map[string]string, error) {
	cmd := exec.Command("git", "remote")
	output, err := cmd.Output()
	if err != nil {
		return nil, fmt.Errorf("获取远程仓库列表失败: %w", err)
	}

	remotes := make(map[string]string)
	for _, remote := range strings.Split(strings.TrimSpace(string(output)), "\n") {
		if remote == "" {
			continue
		}
		url, err := GetRemoteURL(remote)
		if err != nil {
			continue
		}
		remotes[remote] = url
	}

	return remotes, nil
}

// RemoveRemote 删除远程仓库
func RemoveRemote(remoteName string) error {
	cmd := exec.Command("git", "remote", "remove", remoteName)
	if output, err := cmd.CombinedOutput(); err != nil {
		return fmt.Errorf("删除远程仓库失败: %s: %w", string(output), err)
	}
	return nil
}

// ListBranches 列出所有分支（包括远程分支）
func ListBranches(remote string) ([]string, error) {
	// 先获取远程分支信息
	if err := execGitCommand("fetch", remote); err != nil {
		return nil, fmt.Errorf("获取远程分支信息失败: %v", err)
	}

	// 列出所有分支（包括远程分支）
	cmd := exec.Command("git", "branch", "-a")
	output, err := cmd.Output()
	if err != nil {
		return nil, fmt.Errorf("列出分支失败: %v", err)
	}

	branches := make([]string, 0)
	for _, line := range strings.Split(string(output), "\n") {
		// 清理分支名称
		branch := strings.TrimSpace(line)
		branch = strings.TrimPrefix(branch, "*") // 移除当前分支标记
		branch = strings.TrimSpace(branch)
		branch = strings.TrimPrefix(branch, "remotes/"+remote+"/") // 移除远程分支前缀

		if branch != "" && !strings.Contains(branch, "HEAD") {
			// 检查分支是否已添加
			exists := false
			for _, b := range branches {
				if b == branch {
					exists = true
					break
				}
			}
			if !exists {
				branches = append(branches, branch)
			}
		}
	}

	return branches, nil
}

// CheckoutBranch 切换到指定分支
func CheckoutBranch(branch string, create bool) error {
	args := []string{"checkout"}
	if create {
		args = append(args, "-b")
	}
	args = append(args, branch)

	if err := execGitCommand(args...); err != nil {
		return fmt.Errorf("切换分支失败: %v", err)
	}
	return nil
}
